/**
  ******************************************************************************
  * @file           : vfdbsp.c
  * @brief          : Variable-frequency bsp program
  ******************************************************************************
  * @attention
  *
  ******************************************************************************
  */
#include "bsp.h"

#define RS485_DIR_Pin           GPIO_PIN_11
#define RS485_DIR_GPIO_Port     GPIOD
#define RS485_DIR(x)            x?(GPIO_BOP(RS485_DIR_GPIO_Port) = (uint32_t)RS485_DIR_Pin):(GPIO_BC(RS485_DIR_GPIO_Port) = (uint32_t)RS485_DIR_Pin)

/* 110us */
static void rs485_delay(void)
{
	uint16_t i;
	
	for(i=0; i<1375; i++)
	{
		__asm("nop");__asm("nop");
		__asm("nop");__asm("nop");
		__asm("nop");__asm("nop");
		__asm("nop");__asm("nop");
		__asm("nop");__asm("nop");
	}
}

/* USART3 init function */
void RS485_BspInit(void)
{
	rcu_periph_clock_enable(RCU_GPIOC);
  rcu_periph_clock_enable(RCU_GPIOD);
	rcu_periph_clock_enable(RCU_USART5);
	
	gpio_mode_set(RS485_DIR_GPIO_Port, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, RS485_DIR_Pin);
	gpio_output_options_set(RS485_DIR_GPIO_Port, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, RS485_DIR_Pin);
	
	gpio_af_set(GPIOC, GPIO_AF_8, GPIO_PIN_6);
	gpio_af_set(GPIOC, GPIO_AF_8, GPIO_PIN_7);
	
	/* configure USART2 Tx as alternate function push-pull */
	gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_6);
	gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, GPIO_PIN_6);

	/* configure USART2 Rx as alternate function push-pull */
	gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_7);
	gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, GPIO_PIN_7);

	nvic_irq_enable(USART5_IRQn, ROUTE485_UART_IRQ_PRIORITY, 0);
	
  /* USART configure */
	usart_deinit(USART5);
	usart_baudrate_set(USART5, 19200u);
	usart_word_length_set(USART5, USART_WL_8BIT);
	usart_parity_config(USART5, USART_PM_NONE);
	usart_stop_bit_set(USART5, USART_STB_1BIT);
	usart_receive_config(USART5, USART_RECEIVE_ENABLE);
	usart_transmit_config(USART5, USART_TRANSMIT_ENABLE);
	usart_halfduplex_disable(USART5);
	usart_synchronous_clock_disable(USART5);
	
  usart_receiver_timeout_threshold_config(USART5, 250); /* 86.806ms */
	usart_receiver_timeout_enable(USART5);
	
	usart_interrupt_enable(USART5, USART_INT_RBNE);
	usart_interrupt_enable(USART5, USART_INT_RT);
	
	usart_enable(USART5);
  
  RS485_DIR(0);
}

void RS485_Sendbuf(const uint8_t *buf, uint32_t len)
{
	uint32_t i;
  
	RS485_DIR(1);
	rs485_delay();
	
	for(i=0; i<len; i++)
	{
    USART_DATA(USART5) = (buf[i]& (uint16_t)0x01FFU);
    while(!(USART_STAT0(USART5) & USART_STAT0_TBE));
	}
	
	while (!(USART_STAT0(USART5) & USART_STAT0_TC));
	
	rs485_delay();
	RS485_DIR(0);
}

extern void RS485_BreakIsr(void);
extern void RS485_RecvIsr(uint8_t dat);

/**
  * @brief This function handles USART3 global interrupt.
  */
void USART5_IRQHandler(void)
{
	if(usart_interrupt_flag_get(USART5, USART_INT_FLAG_RBNE) != RESET)
	{
		RS485_RecvIsr(USART_DATA(USART5));
	}
  
  if(usart_interrupt_flag_get(USART5, USART_INT_FLAG_RT) != RESET)
	{
		usart_interrupt_flag_clear(USART5, USART_INT_FLAG_RT);

    while(!(USART_STAT0(USART5) & USART_STAT0_TBE));

    RS485_BreakIsr();
  }
}
